package cn.lock.abstracts.impl;

import cn.lock.Sync;
import lombok.Getter;
import lombok.Setter;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 类简介: 异步同步器
 * 如果你不想让你的消息异步的话，你可以使用本类
 * 本类可以非常方便的让你将异步消息转化为同步获取
 *
 * @Author: ShangGuan
 * @Time: 2024/05/31
 **/
public class AsynchronousSynchronizer<T> {
    private final Lock lock = new ReentrantLock();
    private final Condition done = lock.newCondition();

    @Setter
    @Getter
    private Sync<T> sync;


    public AsynchronousSynchronizer() {
    }

    public AsynchronousSynchronizer(Sync<T> sync) {
        this.sync = sync;
    }

    /**
     * 获取异步线程对应的数据
     *
     * @param timeout 阻塞时间
     * @return {@link Object }
     **/
    public T get(int timeout) throws TimeoutException {
        long start = System.nanoTime();
        lock.lock();
        try {
            while (!isDone()) {
                done.await(timeout, TimeUnit.MILLISECONDS);
                long cur = System.nanoTime();
                if (isDone() || cur - start > timeout) {
                    break;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
        if (!isDone()) {
            //如果在限定时间范围外还还没有获取对应的值的话就会报错
            throw new TimeoutException("get result timeout exception");
        }
        return sync.getResult();
    }

    /**
     * 监测结果是否完成
     *
     * @return boolean
     **/
    boolean isDone() {
        return sync.checkDone();
    }


    public void release() {
        lock.lock();
        try {
            done.signal();
        } finally {
            lock.unlock();
        }
    }
}
